Skip to content

fix(cua-driver/linux): libxcb fallback for X11 connect so list_windows works where xdotool does (#1978) - #1991

Open
f-trycua wants to merge 7 commits into
mainfrom
fix/x11-libxcb-fallback-1978
Open

f-trycua wants to merge 7 commits into
mainfrom
fix/x11-libxcb-fallback-1978

Conversation

@f-trycua

@f-trycua f-trycua commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

On some Linux/X11 setups (reported on Ubuntu 22.04 XFCE/lightdm), list_windows / get_window_state return 0 windows and cua-driver doctor reports "X11 is not reachable" — even though apps are running and xdotool / pyatspi enumerate windows fine on the same display. Fixes #1978.

Root cause

x11rb's pure-Rust RustConnection::connect(None) does strict Xauthority family/address cookie matching and returns Err in environments where libxcb-based clients (xdotool, pyatspi, Xlib) connect fine — e.g. an auth entry stored under a hostname/family that doesn't match how x11rb canonicalizes it. list_windows_inner propagated that Err, and list_windows swallowed it into an empty Vec, so the failure surfaced only as "0 windows".

Fix

  • libxcb fallback. Try RustConnection first; on connect failure, fall back to the libxcb-backed XCBConnection (enabled via the x11rb allow-unsafe-code feature) — the same client library xdotool/pyatspi use, so we connect in exactly the environments those tools work in.
  • Generic enumeration. The window-enumeration helpers (enumerate_windows, get_window_list, get_atom, get_window_pid, get_window_title, wm_class_inner) are now generic over C: Connection so both connection types share one code path.
  • No more silent zero. When both connects fail, surface a descriptive error (DISPLAY / XAUTHORITY + both underlying errors) instead of an empty list — so the next report like this is diagnosable from logs.
  • Doctor agreement. probe_x11_connect mirrors the fallback so the doctor verdict matches what list_windows can actually do.

Verification

  • Build-verified on Linux (Ubuntu, x11rb + system libxcb-dev): cargo build -p platform-linux is green with the allow-unsafe-code / XCBConnection path compiled in. Added libxcb-*-dev are standard X11 build deps.
  • Runtime repro not yet captured. The available test fleet has no logged-in X11 desktop session (Wayland greeters / no active seat), so I could not reproduce the original 0-window condition end-to-end. The fix routes through the same libxcb path the working tools use; a maintainer on the reported XFCE/lightdm setup can confirm list_windows now returns the live windows. Calling this out honestly rather than claiming a runtime pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved X11 connectivity reliability on Linux by implementing an alternative connection method when the primary method fails.
    • Enhanced error reporting for X11 connection issues, including diagnostic information to help troubleshoot connectivity problems.
  • Improvements

    • Made window enumeration more robust on Linux systems to align with actual platform capabilities.

Maintainer integration

Current candidate: 5ec39b0b3cb136e053b6007d9b5bd5434049b74d.

  • Rebased the contributor history onto current main without squashing it.
  • Applied the same libxcb fallback to get_window_state ownership validation so windows returned by list_windows are not immediately rejected as stale.
  • Added libxcb to the package, release, runtime, and separate Nix Rust-unit dependency closures.
  • cargo test -p platform-linux --lib --locked: 23 passed; formatting, workflow YAML, and diff checks passed.
  • Fixed the exact Debian bootstrap dependency contract to include libxcb1-dev; its focused three-test suite and the new current-head CI: Driver Linux dependency bootstrap workflow pass.
  • The first current-head Nix unit run exposed the separate test derivation; that exact missing libxcb input is fixed in this candidate and replacement CI is running. Native reproduction of the original XFCE/lightdm Xauthority mismatch remains unavailable in the current fleet.

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jun 24, 2026 2:36am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c8d1e01-02f0-46bc-9654-0be70daf67f4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds allow-unsafe-code to the x11rb Cargo dependency, then refactors X11 window enumeration and WM_CLASS lookup to attempt a pure-Rust RustConnection first and fall back to XCBConnection (libxcb) when the pure-Rust connection fails. Helpers are generalized to C: Connection. The health probe is updated to match the same two-stage strategy.

Changes

X11 libxcb fallback for window enumeration and health probe

Layer / File(s) Summary
Cargo feature flag and module imports
libs/cua-driver/rust/crates/platform-linux/Cargo.toml, libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs
Adds allow-unsafe-code to the x11rb dependency and imports anyhow! and XCBConnection into x11/mod.rs.
Two-stage connection, generic helpers, and wm_class fallback
libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs
Replaces the single RustConnection flow with a RustConnection-first / XCBConnection-fallback strategy in list_windows and wm_class_for_window. Adds x11_connect_error for diagnostic output including DISPLAY/XAUTHORITY. Refactors enumerate_windows, get_window_list, get_atom, get_window_pid, and get_window_title to accept generic C: Connection.
Health probe update
libs/cua-driver/rust/crates/platform-linux/src/health_report.rs
probe_x11_connect returns true when either RustConnection or XCBConnection connects, aligning the health verdict with the new window-enumeration path.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant list_windows
  participant RustConnection
  participant XCBConnection
  participant enumerate_windows

  Caller->>list_windows: list_windows()
  list_windows->>RustConnection: connect(None)
  alt pure-Rust connection succeeds
    RustConnection-->>list_windows: Ok(conn)
    list_windows->>enumerate_windows: enumerate_windows(conn)
  else pure-Rust fails, try libxcb
    RustConnection-->>list_windows: Err(rust_err)
    list_windows->>XCBConnection: connect(None)
    alt libxcb succeeds
      XCBConnection-->>list_windows: Ok(conn)
      list_windows->>enumerate_windows: enumerate_windows(conn)
    else both fail
      XCBConnection-->>list_windows: Err(xcb_err)
      list_windows-->>Caller: Err(x11_connect_error(DISPLAY, XAUTHORITY, rust_err, xcb_err))
    end
  end
  enumerate_windows-->>Caller: Vec<WindowInfo>
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 When the cookie wouldn't match and the windows stayed hidden,
A fallback was added — libxcb unbidden!
RustConnection tries first, then xcb takes the stage,
Generic Connection helpers now span every page.
Zero windows no more — the rabbit hops free! 🪟✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title directly describes the main fix: adding libxcb fallback for X11 connection to enable list_windows in environments where xdotool works.
Linked Issues check ✅ Passed PR fully addresses issue #1978 requirements: implements libxcb fallback for X11 connection failures, refactors window enumeration to support both connection types, improves error messaging, and updates health diagnostics.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing X11 window enumeration via libxcb fallback. Modifications to Cargo.toml, health_report.rs, and x11/mod.rs are all necessary for the stated fix.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/x11-libxcb-fallback-1978

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Linux visual regression artifacts

Matrix jobs now run independently. Download visual artifacts from this workflow run.
Each background-GUI job uploads a .gif of the interaction plus two annotated PNGs (<app>.png raw, <app>-atspi.png with AT-SPI element boxes); the cua-driver-linux-som-overlays artifact adds <app>-som.png cua Set-of-Marks overlays:

  • cua-driver-linux-cursor-click-gif
  • cua-driver-linux-background-terminal-gif
  • cua-driver-linux-parallel-drag-xserver
  • cua-driver-linux-background-gui-chromium
  • cua-driver-linux-background-gui-tk
  • cua-driver-linux-background-gui-gtk3-gedit
  • cua-driver-linux-background-gui-gtk3-mousepad
  • cua-driver-linux-background-gui-gtk3-scite
  • cua-driver-linux-background-gui-gtk4-characters
  • cua-driver-linux-background-gui-qt5-manuskript
  • cua-driver-linux-background-gui-qt5-klog
  • cua-driver-linux-background-gui-qt5-openambit
  • cua-driver-linux-background-gui-qt6-kate
  • cua-driver-linux-background-gui-qt6-kcalc
  • cua-driver-linux-background-gui-qt6-okular
  • cua-driver-linux-background-gui-qt6-qownnotes
  • cua-driver-linux-background-gui-electron-zettlr
  • cua-driver-linux-background-gui-electron-joplin
  • cua-driver-linux-background-gui-electron-logseq
  • cua-driver-linux-som-overlays

Open workflow run and download artifacts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs (1)

160-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: factor out the duplicated connect-then-fallback logic.

wm_class_for_window repeats the same RustConnection→XCBConnection strategy as list_windows_inner, but in a different shape (sequential if let vs match). A small generic helper that runs a closure against whichever connection succeeds would keep the two call sites from drifting (e.g., if a third connect strategy or a timeout is added later).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs` around lines 160 -
169, The wm_class_for_window function duplicates the
RustConnection→XCBConnection fallback pattern already present in
list_windows_inner. Extract this common connection-retry logic into a generic
helper function that accepts a closure parameterized over the connection type,
then refactor both wm_class_for_window and list_windows_inner to use this shared
helper instead of repeating the sequential if-let connection attempts. This
prevents the two implementations from drifting apart if future changes (like
adding a third strategy or timeout handling) are needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/cua-driver/rust/crates/platform-linux/Cargo.toml`:
- Line 24: The x11rb dependency in Cargo.toml with the `allow-unsafe-code`
feature enabled requires the system libxcb library to be available at build time
for FFI bindings, but the build and CI environments do not currently provision
libxcb-dev. To fix this, update your Dockerfile to install libxcb-dev as part of
the build stage, and update all CI workflow manifests to install libxcb-dev
before running build and test steps. This ensures the system has the required
development headers available when linking against x11rb with
`allow-unsafe-code` enabled.

---

Nitpick comments:
In `@libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs`:
- Around line 160-169: The wm_class_for_window function duplicates the
RustConnection→XCBConnection fallback pattern already present in
list_windows_inner. Extract this common connection-retry logic into a generic
helper function that accepts a closure parameterized over the connection type,
then refactor both wm_class_for_window and list_windows_inner to use this shared
helper instead of repeating the sequential if-let connection attempts. This
prevents the two implementations from drifting apart if future changes (like
adding a third strategy or timeout handling) are needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: afb8f180-3c67-45d8-98df-ea7d14c850f0

📥 Commits

Reviewing files that changed from the base of the PR and between c898d7b and 4fb723d.

📒 Files selected for processing (3)
  • libs/cua-driver/rust/crates/platform-linux/Cargo.toml
  • libs/cua-driver/rust/crates/platform-linux/src/health_report.rs
  • libs/cua-driver/rust/crates/platform-linux/src/x11/mod.rs

Comment thread libs/cua-driver/rust/crates/platform-linux/Cargo.toml Outdated
@f-trycua

Copy link
Copy Markdown
Collaborator Author

CI now green (minus the known cursor-click-gif flake).

Root cause of the broad CI failure (real regression, not flake)

Enabling the x11rb allow-unsafe-code feature compiles its xcb_ffi module (the libxcb-backed XCBConnection fallback), which pulled in a new transitive crate and a new linked C library that no build manifest declared. This broke in two layers:

  1. Cargo.lock was missing as-raw-xcb-connection (+ the libc/as-raw-xcb-connection edges on x11rb). The original validation build ran online so cargo fetched it silently; CI’s Nix build runs cargo build --offline against a vendored dir and failed at dependency resolution (no matching package named as-raw-xcb-connection found) — before any test ran, which is why every Linux job failed identically.
  2. libxcb was not linked. xcb_ffi emits cargo:rustc-link-lib=xcb, so the binary now hard-links libxcb, but nix/cua-driver/package.nix (and the CD/distro-compat workflows) never provided it → collect2: ld returned 1 exit status (-lxcb with no matching -L).

Fix

  • Cargo.lock: vendor as-raw-xcb-connection (minimal in-place resolve).
  • nix/cua-driver/package.nix: add libxcb to buildInputs.
  • cd-rust-cua-driver.yml: add libxcb1-dev (release build).
  • ci-distro-compat-cua-driver.yml: add libxcb1/libxcb runtime lib for every distro (the released binary now loads libxcb at runtime).
  • Rebased onto current main (8 PRs merged since branch point; health_report.rs rebased clean).

Status

67 pass / 3 fail. The only red checks are gnome|kde|xfce-labwc / cursor-click-gif — the known flake (fails on current main and on Windows-only PRs too; was the sole red check on all 8 merged sibling PRs in this batch). Non-gif failures: 0.

f-trycua and others added 4 commits September 13, 2026 04:13
…s works where xdotool does (#1978)

x11rb's pure-Rust RustConnection::connect does strict Xauthority
family/address cookie matching and returns Err in some setups (XFCE/lightdm,
hostname-mismatched auth entries) where libxcb-based tools (xdotool, pyatspi)
connect fine. list_windows then silently returned 0 windows and the health
report said "X11 is not reachable", despite a working X session.

- Try RustConnection first, fall back to the libxcb XCBConnection (enabled via
  x11rb allow-unsafe-code) — same client lib xdotool/pyatspi use.
- Make the window-enumeration helpers generic over the connection type.
- When BOTH connects fail, surface a descriptive error (DISPLAY/XAUTHORITY +
  both underlying errors) instead of collapsing to an empty list.
- Mirror the fallback in the doctor's probe_x11_connect so the verdict matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
… x11rb xcb-ffi (#1978)

Enabling the x11rb `allow-unsafe-code` feature pulls in the `xcb_ffi`
module, which depends on `as-raw-xcb-connection` (+ libc) — crates that
were not in the committed Cargo.lock. The earlier VM build that validated
this change ran online, so cargo fetched the new crate transparently; CI's
Nix build runs `cargo build --offline` against a vendored dir and failed
with "no matching package named `as-raw-xcb-connection` found", breaking
every Linux integration job (build-time, before any test ran).

Add the package + the two new x11rb dependency edges to Cargo.lock so the
offline/vendored build resolves. Minimal in-place update (cargo metadata),
no unrelated version churn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
…fi (#1978)

The x11rb `allow-unsafe-code` feature compiles its `xcb_ffi` module (the
libxcb-backed XCBConnection fallback for strict-Xauthority setups, #1978),
which emits `cargo:rustc-link-lib=xcb`. The cua-driver binary therefore now
hard-links libxcb, but none of the build manifests provided it:

- nix/cua-driver/package.nix: link failed with `-lxcb` and no matching `-L`
  ("collect2: ld returned 1 exit status") in every nix VM test. Add `libxcb`
  to buildInputs; update the stale "x11rb -> no libxcb C binding" comment.
- cd-rust-cua-driver.yml: the debian:11 release build would fail the same
  way. Add `libxcb1-dev`.
- ci-distro-compat-cua-driver.yml: the released binary now needs the libxcb
  runtime lib at load time; add `libxcb1` (deb) / `libxcb` (rpm) to every
  distro's runtime install so --version doesn't exit 127 on an ABI error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
Apply the same connection fallback when get_window_state validates an X11 window owner, so a strict Xauthority mismatch cannot make a freshly listed target look stale.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@f-trycua
f-trycua force-pushed the fix/x11-libxcb-fallback-1978 branch from aa7558b to 2184d9a Compare September 13, 2026 09:17
@f-trycua
f-trycua requested a review from injaneity as a code owner September 13, 2026 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux: list_windows returns 0 despite apps running, AT-SPI tree accessible but no window elements

2 participants